﻿using System;
using System.Collections.Generic;
using System.Text;
using StarBotDotNet;

namespace StarBotDotNet
{

    public abstract class UnitParty : UnitDictionary, IComparable<UnitParty>
    {


        public abstract void ExecuteTactics(ProxyBot bot, UnitDictionary currentUnits, int currentTime);

        public abstract int Priority
        {
            get;
        }

        public Dictionary<StarBotDotNet.UnitType, int> PresentUnits
        {
            get
            {
                Dictionary<StarBotDotNet.UnitType, int> present = new Dictionary<UnitType, int>();
                foreach (UnitData unit in this.GetAllUnits())
                {

                    if (!present.ContainsKey(unit.Type))
                    {
                        present[unit.Type] = 0;
                    }
                    present[unit.Type]++;
                }

                return present;
            }
        }

        public abstract Dictionary<UnitType, int> RequiredUnits
        {
            get;
        }


        #region IComparable<UnitParty> Members

        public int CompareTo(UnitParty other)
        {
            return other.Priority.CompareTo(this.Priority);

        }

        public override int GetHashCode()
        {
            return this.Priority;
        }

        #endregion

        internal bool NeedsUnit(UnitData un)
        {
            if (!RequiredUnits.ContainsKey(un.Type))
            {
                return false;
            }

            if (!PresentUnits.ContainsKey(un.Type))
            {
                if (RequiredUnits[un.Type] > 0)
                {
                    return true;
                }
            }

            if (PresentUnits[un.Type] < RequiredUnits[un.Type])
            {
                return true;

            }

            return false;
        }



        internal virtual void PopulateWithUnits(ProxyBot bot, UnitDictionary currentUnits, List<UnitData> discoveredUnits, List<UnitData> dissapearedUnits, int currentTime)
        {

            foreach (UnitData un in currentUnits.GetAllUnits())
            {
                if (un.OwnedByPlayer)
                {
                    if (currentUnits.GetParty(un) == null)
                    {
                        if (NeedsUnit(un))
                        {
                            if(!un.IsIdle)
                            {
                                bot.stop(un.ID);
                            }
                            Add(un, this);
                            currentUnits.SetParty(un, this);
                        }
                    }
                }
            }

            foreach (UnitType type in this.PresentUnits.Keys)
            {
                //Free the unit

                while (HasTooMany(type))
                {
                    UnitData data = RemoveUnused(type);
                    if (data == null)
                    {
                        Utilities.WriteColorLine(ConsoleColor.Red, "WARNING: PopulateWithUnits function called RemoveUnused and was returned null");
                       //Console.WriteLine("WARNING: PopulateWithUnits function called RemoveUnused and was returned null");
                        break;
                    }
                    else
                    {
                        currentUnits.SetParty(data, null);
                    }
                }
            }
        }

        public UnitData RemoveUnused(UnitType type)
        {
            UnitData data = FindUnused(type);
            this.Remove(data);
            return data;
        }

        private UnitData FindUnused(UnitType type)
        {
            foreach (UnitData data in GetAllUnits())
            {
                if (data.Type == type)
                {
                    if (IsUnused(data))
                    {
                        return data;
                    }

                }

            }

            return null;
        }

        protected abstract bool IsUnused(UnitData data);

        public virtual bool HasTooMany(UnitType type)
        {
            if (!PresentUnits.ContainsKey(type))
            {
                return false;
            }

            if (!RequiredUnits.ContainsKey(type))
            {
                if (PresentUnits[type] > 0)
                {
                    return true;
                }
            }

      

            if (PresentUnits[type] > RequiredUnits[type])
            {
                return true;
            }

            return false;
        }

    }
}
